package com.yami.shop.personnft.common.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailException;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.util.StringUtil;
import com.google.common.collect.Lists;
import com.yami.shop.bean.enums.SceneType;
import com.yami.shop.bean.enums.TradeType;
import com.yami.shop.bean.event.*;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.vo.AssetTrendsVO;
import com.yami.shop.bean.vo.DawToVo;
import com.yami.shop.bean.vo.PersonnftProdVo;
import com.yami.shop.common.bean.Minio;
import com.yami.shop.common.bean.PageDTO;
import com.yami.shop.common.bean.PageVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.response.ResponseEnum;
import com.yami.shop.common.util.*;
import com.yami.shop.common.util.pdfUtil.PdfUtils;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.nft.common.model.NftApply;
import com.yami.shop.nft.common.service.NftApplyService;
import com.yami.shop.personnft.common.dao.PersonNftAccountMapper;
import com.yami.shop.personnft.common.dao.PersonNftApplyMapper;
import com.yami.shop.personnft.common.dao.PersonNftMapper;
import com.yami.shop.personnft.common.model.PersonNft;
import com.yami.shop.personnft.common.model.PersonNftAccount;
import com.yami.shop.personnft.common.model.TransferApplyRecord;
import com.yami.shop.personnft.common.model.TransferBatchApply;
import com.yami.shop.personnft.common.service.*;
import com.yami.shop.service.*;
import com.yami.shop.user.common.service.UserGasLogService;
import com.yami.shop.webservice.common.service.TransferTokenRecordService;
import com.yami.shop.webservice.common.service.WapiDawService;
import lombok.AllArgsConstructor;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.yami.shop.bean.enums.SendType.SUBGIFT;

@Slf4j
@Service
@AllArgsConstructor
public class PersonNftApplyServiceImpl implements PersonNftApplyService {

	@Autowired
    private PersonNftApplyMapper personNftApplyMapper;
	@Autowired
	private PersonNftMapper personNftMapper;
	@Autowired
	private PersonNftAccountMapper personNftAccountMapper;
	@Autowired
	private UserService userService;
	@Autowired
	private ShopConfig shopConfig;
	@Autowired
	private PersonNftService personNftService;
	@Autowired
	private ProductService productService;
	@Autowired
	private TransferTokenRecordService transferTokenRecordService;
	@Autowired
	private OrderService orderService;
	@Resource
	private TransactionDefinition transactionDefinition;
	@Resource
	private DataSourceTransactionManager dataSourceTransactionManager;
	@Autowired
	private WapiDawService wapiDawService;
	@Autowired
	private TransferApplyService transferApplyService;
	@Autowired
	private NftTansferEnpandService nftTansferEnpandService;
	@Autowired
	private DataWebService dataWebService;
	@Autowired
	private NotifyTemplateService notifyTemplateService;

	@Autowired
	private ChannelUserRelationRecordService channelUserRelationRecordService;
	@Autowired
	private ApplicationContext applicationContext;
	@Autowired
	private UserGasLogService userGasLogService;
	@Autowired
	private PersonnftThanfserRefundService personnftThanfserRefundService;
	@Autowired
	private TransferBatchApplyService transferBatchApplyService;
	@Autowired
	private ProdNftService prodNftService;
	private final ApplicationEventPublisher eventPublisher;
	@Autowired
	private BlockchainService blockchainService;
	@Autowired
	private AttachFileService attachFileService;
	@Autowired
	private NftApplyService nftApplyService;

	@Override
	public List<PersonNftApply> listByParam(PersonNftApply personNftApply) {
		return personNftApplyMapper.listByParam(personNftApply);
	}

	@Override
	public void save(PersonNftApply personNftApply) {
		personNftApplyMapper.save(personNftApply);
	}
	@Transactional
	@Override
	public String saveTransferHwjApplyBatch(PersonNftApply personNftApply) {
		String id = IdUtil.getSnowflake().nextIdStr();
		String userId = personNftApply.getUserId();
		String collect1 = "";
		String collect3 = "";
		String denomId = "";
		ProdNft dataByProdId = null;
		Product synchronizationprod = null;
		if("2".equals(personNftApply.getChannelType())){
			synchronizationprod = productService.getSynchronizationprod(personNftApply.getChainCode(), personNftApply.getChannelCode(), String.valueOf(personNftApply.getProductId()));
			dataByProdId = prodNftService.getDataByProdId(synchronizationprod.getProdId());
		}else{
			dataByProdId = prodNftService.getDataByProdId(personNftApply.getProductId());
		}
		userGasLogService.reduceGasNumberThansferByUserId(userId,personNftApply.getCount(),6,personNftApply.getChannelCode(),personNftApply.getChainCode(),null);
		if("1".equals(personNftApply.getChannelType())){
			personNftApply.setDay(ObjectUtil.isNull(dataByProdId.getTransferPreDayNum())?0:(int) dataByProdId.getTransferPreDayNum());
			//随机获取持仓不冻结，t+n ，兑换权益没有使用过
			List<PersonNft> list = personNftMapper.getTransferlistByParamCountLimit(userId,personNftApply.getProductId(),personNftApply.getDay(),personNftApply.getCount());
			if(personNftApply.getCount()!=list.size()){
				throw new YamiShopBindException("资产不足");
			}
			collect1 = list.stream().map(PersonNft::getTokenId).collect(Collectors.joining(","));
			collect3  = list.stream().map(PersonNft::getDawProductCode).collect(Collectors.joining(","));
			denomId = list.get(0).getDenomId();
			//修改审核状态
			for (PersonNft personNft:list) {
				personNft.setStatus(1);
			}
			personNftMapper.updateBatchById(list);
		}else{
			//下游持仓token
			ChannelUserRelationRecord record = channelUserRelationRecordService.getinfoByUserIdChainCodeChannelCode(personNftApply.getUserId(), personNftApply.getChainCode(), personNftApply.getChannelCode(), personNftApply.getChannelType());
			//下游增用户
			String channelUserId = record.getChannelUserId();
			Map<String,String> obj = new HashMap<>();
			obj.put("userId",channelUserId);
			obj.put("channelCode",personNftApply.getChannelCode());
			obj.put("chainCode",personNftApply.getChainCode());
			obj.put("count",personNftApply.getCount().toString());
			obj.put("productId",personNftApply.getProductId().toString());
			obj.put("sceneType","3");
			String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/freeze?";
			JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
			if(jsonObject.getInteger("code")== Constant.WARN){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new YamiShopBindException("最大可划转数量为"+jsonObject.getString("msg"));
			}
			if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new MailException("冻结失败");
			}
			JSONObject data = jsonObject.getJSONObject("data");
			personNftApply.setDownApplyId(data.getString("applyId"));
			denomId = data.getString("denomId");
			collect1 = data.getString("tokensIds");
			collect3 = data.getString("productCodes");
			personNftApply.setProductId(synchronizationprod.getProdId());//更换dtc商品id
		}
		PersonNftApply personNftApply1 = PersonNftApply.builder()
				.createTime(DateUtil.date())
				.id(id)
				.content(collect1)
				.sceneType("3")
				.dawProductCode(collect3)
				.status(0)
				.hwjUserId(personNftApply.getHwjUserId())
				.count(personNftApply.getCount())
				.denomId(denomId)
				.isListClick(personNftApply.getIsListClick())
				.userId(userId)
				.productId(personNftApply.getProductId())
				.channelCode(personNftApply.getChannelCode())
				.chainCode(personNftApply.getChainCode())
				.channelType(personNftApply.getChannelType())
				.downApplyId(personNftApply.getDownApplyId())
				.build();
		personNftApplyMapper.save(personNftApply1);
		return id;
	}

	@Override
	public IPage<PersonNftApply> page(PageParam pageDTO, PersonNftApply personNftApply) {
		IPage<PersonNftApply> doPage = personNftApplyMapper.listPageByParam(pageDTO,personNftApply);
		return doPage;
	}
	@Transactional
	@Override
	public String saveTransferApply(PersonNftApply personNftApply) {
		String id = IdUtil.getSnowflake().nextIdStr();
		String userId = personNftApply.getUserId();
		String collect1 = "";
		String collect3 = "";
		String denomId = "";
		String prodName = "";

		if("1".equals(personNftApply.getChannelType())){
			//随机获取持仓
			List<PersonNft> list = personNftMapper.getlistByParamCountLimit(userId,personNftApply.getProductId(),personNftApply.getCount());
			if(personNftApply.getCount()!=list.size()){
				throw new YamiShopBindException("资产不足");
			}
			collect1 = list.stream().map(PersonNft::getTokenId).collect(Collectors.joining(","));
			collect3 = list.stream().map(PersonNft::getDawProductCode).collect(Collectors.joining(","));
			//修改审核状态
			for (PersonNft personNft:list) {
				personNft.setStatus(1);
				personNft.setUpdateTime(DateUtil.date());
			}
			personNftMapper.updateBatchById(list);
			denomId = list.get(0).getDenomId();

			//待获取商品名称productName
			Product productByProdId = productService.getProductByProdId(personNftApply.getProductId());
			prodName = productByProdId.getProdName();
		}else{
			//下游持仓token
			ChannelUserRelationRecord record = channelUserRelationRecordService.getinfoByUserIdChainCodeChannelCode(personNftApply.getUserId(), personNftApply.getChainCode(), personNftApply.getChannelCode(), personNftApply.getChannelType());
			//下游增用户
			String channelUserId = record.getChannelUserId();
			//下游受增用户
			String toUserId = personNftApply.getToUserId();

			Map<String,String> obj = new HashMap<>();
			obj.put("userId",channelUserId);
			obj.put("toUserId",toUserId);
			obj.put("channelCode",personNftApply.getChannelCode());
			obj.put("chainCode",personNftApply.getChainCode());
			obj.put("count",personNftApply.getCount().toString());
			obj.put("productId",personNftApply.getProductId().toString());
			obj.put("sceneType","1");
			String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/freeze?";
			JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
			if(jsonObject.getInteger("code")== Constant.WARN){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new YamiShopBindException("最大可转增数量为"+jsonObject.getString("msg"));
			}
			if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new MailException(jsonObject.getString("msg"));
			}
			JSONObject data = jsonObject.getJSONObject("data");
			personNftApply.setDownApplyId(data.getString("applyId"));
			denomId = data.getString("denomId");
			collect1 = data.getString("tokensIds");
			collect3 = data.getString("productCodes");
			Product product = productService.getSynchronizationprod(personNftApply.getChainCode(), personNftApply.getChannelCode(), String.valueOf(personNftApply.getProductId()));
			personNftApply.setProductId(product.getProdId());//更换dtc商品id
			prodName = product.getProdName();
			ChannelUserRelationRecord userByChannelUserId = channelUserRelationRecordService.getUserByChannelUserId(personNftApply.getToUserId(), personNftApply.getChainCode(), personNftApply.getChannelCode());
			if(!ObjectUtil.isNull(userByChannelUserId)){
				personNftApply.setToUserId(userByChannelUserId.getUserId());//如果转入的用户有导入，存入dtc对应的userid
			}
		}

		personNftApply.setCreateTime(DateUtil.date());
		personNftApply.setId(id);

		personNftApply.setContent(collect1);
		personNftApply.setSceneType("1");

		personNftApply.setDawProductCode(collect3);
		personNftApply.setStatus(0);
		personNftApply.setDenomId(denomId);
		personNftApply.setUserId(userId);
		//渠道店铺编码都已带入
		personNftApplyMapper.save(personNftApply);

		log.info("转增1天过期mq=======================");
		//生成GAS余额充值日志
		userGasLogService.reduceGasNumberThansferByUserId(userId,personNftApply.getCount(),3,personNftApply.getChannelCode(),personNftApply.getChainCode(),personNftApply.getToUserId());
		notifyTemplateService.sendNotifyByUserSubgift(personNftApply, prodName, SUBGIFT);
		//发送定时器
		RersonnftThanfserRefund rersonnftThanfserRefund = new RersonnftThanfserRefund();
		rersonnftThanfserRefund.setApplyId(id);
		rersonnftThanfserRefund.setCreateTime(DateUtil.date());
		rersonnftThanfserRefund.setStatus(0);
		rersonnftThanfserRefund.setRefundTime(DateUtil.offsetDay(DateUtil.date(),1));
		personnftThanfserRefundService.save(rersonnftThanfserRefund);
		return id;
	}

	@Override
	public PersonNftApply getinfoById(String id) {
		return personNftApplyMapper.getinfoById(id);
	}

	@Override
	public void update(PersonNftApply personNftApply) {
		personNftApplyMapper.update(personNftApply);
	}

	@Override
	public void updateByDownApplyId(PersonNftApply personNftApply) {
		personNftApplyMapper.updateByDownApplyId(personNftApply);
	}

	@Override
	public void updateTransferApply(PersonNftApply personNftApply) {
		String type = personNftApply.getType();
		if(type.equals("2")){
			//驳回
			personNftApply.setStatus(2);
			transferReject(personNftApply);
		}else{//接收
			transferAgree(personNftApply);
		}
	}
	//转增同意
	private void transferAgree(PersonNftApply personNftApply){
		if("2".equals(personNftApply.getChannelType())){
			//下游同意
			transferAgreeDown(personNftApply);
			return;
		}
		//dtc通过  事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		try {
			List<PersonNft> lsit = new ArrayList<>();
			String[] tokenIds = personNftApply.getContent().split(",");
			List<PersonNft> lsitAdd = new ArrayList<>();
			for (String tokenId: tokenIds) {
				//1增加受赠方持仓
				PersonNft personNft = PersonNft.builder().tokenId(tokenId).build();
				List<PersonNft> personNfts = personNftMapper.listByParam(personNft);
				//校验受赠方是否有该未删除的tokenid
				List<PersonNft> list = personNfts.stream().filter(s -> s.getUserId().equals(personNftApply.getToUserId())&&s.getStatus()!=2).collect(Collectors.toList());
				if(list.size()>1){
					log.info("接收-受赠方持仓数据异常，转增记录id="+personNftApply.getId());
					throw new YamiShopBindException("受赠方持仓数据异常");
				}
				List<PersonNft> list1 = personNfts.stream().filter(s -> s.getUserId().equals(personNftApply.getToUserId())&&s.getStatus()==2).collect(Collectors.toList());

				//4 转增方减去持仓
				List<PersonNft> personNfts2 = personNfts.stream().filter(s -> s.getUserId().equals(personNftApply.getUserId())&&s.getStatus()==1).collect(Collectors.toList());
				if(personNfts2.size()!=1){
					log.info("接收-转增方持仓数据异常，转增记录id="+personNftApply.getId());
					throw new YamiShopBindException("转赠方持仓数据异常");
				}else{
					//受赠方减去持仓
					PersonNft personNft1 = personNfts2.get(0);
					personNft1.setStatus(2);
					personNft1.setUpdateTime(DateUtil.date());
					lsit.add(personNft1);
				}

				if(list1.size()>0){
					//如果受赠方已有记录直接修改状态
					PersonNft personNft1 = list1.get(0);
					personNft1.setStatus(0);
					personNft1.setSceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()));
					personNft1.setUpdateTime(DateUtil.date());
					personNft1.setCreateTime(DateUtil.date());
					lsit.add(personNft1);
				}else{

					//受赠方添加持仓 -没有新增一条
					PersonNft personNft1 = personNfts.get(0);
					PersonNft person = PersonNft.builder()
							.status(0)
							.id(IdUtil.getSnowflake().nextIdStr())
							.createTime(DateUtil.date())
							.userId(personNftApply.getToUserId())
							.tokenId(tokenId)
							.productId(personNftApply.getProductId())
							.dawProductCode(personNft1.getDawProductCode())
							.denomId(personNftApply.getDenomId())
							.channelCode(personNftApply.getChannelCode())
							.chainCode(personNftApply.getChainCode())
							.sceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()))
							.build();
					// 修改文件
					NftApply nftApply = nftApplyService.getNftApplyAndImgInfoByDenomId(personNftApply.getDenomId());
					if(nftApply.getNftApplyImg().getIsReplaceUrl() == 1){
						String sourceUrlPdf = JSONObject.parseObject(nftApply.getNftApplyImg().getImgUrl()).getString("sourceUrlPdf");
						// 获取用户 实名 信息
						User user = userService.getUserByUserId(personNftApply.getToUserId());
						// 上传文件信息
						Map<String, Object> keyWordMap = new HashMap<>();
						keyWordMap.put("name",user.getRealName());
						person.setSourceUrl(updateSourceImg(keyWordMap,sourceUrlPdf));
					}
					lsitAdd.add(person);

				}


				// 权益转移修改
				applicationContext.publishEvent(new UpdateRightsEvent(tokenId,personNftApply.getUserId(),personNftApply.getToUserId()));
				// 产证转移数据修改 -- 暂时不需要
//				applicationContext.publishEvent(new UpdateCopyrightEvent(tokenId,personNftApply.getUserId(),personNftApply.getToUserId()));
				log.info("转增成功,权益转移*******************");
			}
			//保存持仓或者删除持仓
			log.info("转增修改持仓数据转增记录id={},数据{}",personNftApply.getId(), Json.toJsonString(lsit));
			if(lsit.size()>0){
				personNftService.updateBatchById(lsit);
			}
			log.info("转增新增持仓数据转增记录id={},数据{}",personNftApply.getId(), Json.toJsonString(lsitAdd));
			if(lsitAdd.size()>0){
				personNftService.saveBatch(lsitAdd);
			}
			saveAccount(personNftApply);
			log.info("转增修改持仓完成=================进入转赠记账");
			//6发起mq修改资产DOTO 转增记账
			List<AssetTrendsVO> list = new ArrayList<>();
			for (String tokenId : tokenIds) {
				AssetTrendsVO trendsVO = AssetTrendsVO.builder().denomId(personNftApply.getDenomId()).tokenId(tokenId)
						.fromUserId(personNftApply.getUserId()).toUserId(personNftApply.getToUserId())
						.price(0.0).outId(personNftApply.getId()).prodId(personNftApply.getProductId()).build();
				list.add(trendsVO);
			}
			applicationContext.publishEvent(new AssetTrendsEvent(TradeType.RE_GIFT.getValue(), list));
			log.info("转增成功，转赠记账完成=================");
			//手动提交事务
			dataSourceTransactionManager.commit(transactionStatus);
		}catch (Exception e){
			e.getMessage();
			//手动回滚事务
			dataSourceTransactionManager.rollback(transactionStatus);
			throw new YamiShopBindException(e.getMessage());
		}

	}
	//下游转增
	private void transferAgreeDown(PersonNftApply personNftApply){
		//事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		try {
			saveAccount(personNftApply);
			Map<String,String> obj = new HashMap<>();
			obj.put("id",personNftApply.getDownApplyId());
			obj.put("type","1");
			obj.put("channelCode",personNftApply.getChannelCode());
			String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/transferPerson?";
			JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
			if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new YamiShopBindException(jsonObject.getString("msg"));
			}
			//手动提交事务
			dataSourceTransactionManager.commit(transactionStatus);
		}catch (Exception e){
			//手动回滚事务
			dataSourceTransactionManager.rollback(transactionStatus);
			if (!ObjectUtil.isNull(e.getMessage()) && e.getMessage().contains("领取")){
				acceptApply(personNftApply);
				throw new YamiShopBindException(e.getMessage());
			}else if(!ObjectUtil.isNull(e.getMessage()) && e.getMessage().contains("拒收")){
				rejectionApply(personNftApply);
				throw new YamiShopBindException(e.getMessage());
			}
			throw new MailException(e.getMessage());
		}
	}
	//转增保存账单并修改完成申请表
	private void saveAccount(PersonNftApply personNftApply){
		//2增加受赠方藏品记录
		PersonNftAccount personNftAccount = PersonNftAccount.builder()
				.sceneType(Integer.valueOf(SceneType.AddByTransfer.getCode()))
				.content(personNftApply.getContent())
				.dawProductCode(personNftApply.getDawProductCode())
				.channelType(personNftApply.getChannelType())
				.denomId(personNftApply.getDenomId())
				.userId(personNftApply.getToUserId())
				.createTime(DateUtil.date())
				.id(cn.hutool.core.util.IdUtil.getSnowflake().nextIdStr())
				.count(personNftApply.getCount())
				.productId(personNftApply.getProductId())
				.channelCode(personNftApply.getChannelCode())
				.chainCode(personNftApply.getChainCode())
				.type(1)
				.orderId(personNftApply.getId())
				.build();
		personNftAccountMapper.save(personNftAccount);
		//5 转增方转增记录
		PersonNftAccount personNftAccount1 = PersonNftAccount.builder()
				.sceneType(Integer.valueOf(SceneType.ReduceByTransfer.getCode()))
				.content(personNftApply.getContent())
				.dawProductCode(personNftApply.getDawProductCode())
				.channelType(personNftApply.getChannelType())
				.denomId(personNftApply.getDenomId())
				.userId(personNftApply.getUserId())
				.createTime(DateUtil.date())
				.id(IdUtil.getSnowflake().nextIdStr())
				.count(personNftApply.getCount())
				.productId(personNftApply.getProductId())
				.channelCode(personNftApply.getChannelCode())
				.type(1)
				.chainCode(personNftApply.getChainCode())
				.orderId(personNftApply.getId())
				.build();
		personNftAccountMapper.save(personNftAccount1);
		personNftApply.setStatus(1);
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
	}

	//转增驳回过期，下游可能已经处理通知失败，采用手动事务修改申请状态
	private void transferReject(PersonNftApply personNftApply) {
		//事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		log.info("转增超时拒收持仓数据转增记录id={}", personNftApply.getId());
		personNftApply.setStatus(personNftApply.getStatus());
		personNftApply.setRemark(personNftApply.getStatus()==2?"用户自己拒收":"超时过期");
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
		//处理退还能量值
		userGasLogService.saveGasNumberThansferByUserId(personNftApply.getUserId(), personNftApply.getCount(),3, personNftApply.getChannelCode(), personNftApply.getChainCode(),null);
		if("1".equals(personNftApply.getChannelType())){
			try{
				upUnFreeze(personNftApply);
				//手动提交事务
				dataSourceTransactionManager.commit(transactionStatus);
			}catch (Exception e){
				//手动回滚事务
				dataSourceTransactionManager.rollback(transactionStatus);
				throw new YamiShopBindException(e.getMessage());
			}
		}else{
			try{
				downUnFreeze(personNftApply);
				//手动提交事务
				dataSourceTransactionManager.commit(transactionStatus);
			}catch (Exception e){
				//手动回滚事务
				dataSourceTransactionManager.rollback(transactionStatus);
				if (!ObjectUtil.isNull(e.getMessage()) && e.getMessage().contains("领取")){
					acceptApply(personNftApply);
					throw new YamiShopBindException(e.getMessage());
				}else if(!ObjectUtil.isNull(e.getMessage()) && e.getMessage().contains("拒收")){
					rejectionApply(personNftApply);
					throw new YamiShopBindException(e.getMessage());
				}
				throw new MailException(e.getMessage());
			}
		}
	}

	private void acceptApply(PersonNftApply personNftApply) {
		personNftApply.setStatus(1);
		personNftApply.setRemark("下游领取");
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
	}

	private void rejectionApply(PersonNftApply personNftApply) {
		personNftApply.setStatus(2);
		personNftApply.setRemark("下游拒收");
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
	}

	//划转驳回
	public void rejectCeceiptApply(String id, String remark) {
		PersonNftApply personNftApply = personNftApplyMapper.getinfoById(id);
		personNftApply.setStatus(2);
		personNftApply.setRemark(remark);
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
		//处理退还能量值
		userGasLogService.saveGasNumberThansferByUserId(personNftApply.getUserId(),personNftApply.getCount(),6,personNftApply.getChannelCode(),personNftApply.getChainCode(),null);
		if("1".equals(personNftApply.getChannelType())){
			//dtc修改持仓审核状态 审核状态改为正常
			upUnFreeze(personNftApply);
		}else {
			//下游解冻
			downUnFreeze(personNftApply);
		}
	}
	//dtc持仓解冻
	private void upUnFreeze(PersonNftApply personNftApply) {
		String[] tokenIds = personNftApply.getContent().split(",");
		List<PersonNft> lsit = new ArrayList<>();
		//修改持仓状态 解冻
		for (String tokenId: tokenIds) {
			PersonNft personNft = PersonNft.builder().tokenId(tokenId).userId(personNftApply.getUserId()).status(1).build();
			//解冻 持仓状态
			List<PersonNft> personNfts = personNftService.listByParam(personNft);
			if(personNfts ==null || personNfts.size()!=1){
				log.info("持仓数据异常，申请记录id="+ personNftApply.getId());
			}
			PersonNft personNft1 = personNfts.get(0);
			personNft1.setUpdateTime(DateUtil.date());
			personNft1.setStatus(0);
			lsit.add(personNft1);
		}
		personNftService.updateBatchById(lsit);
	}
	//下游解冻
	private void downUnFreeze(PersonNftApply personNftApply) {
		//下游解冻
		Map<String,String> obj = new HashMap<>();
		obj.put("id",personNftApply.getDownApplyId());
		obj.put("channelCode",personNftApply.getChannelCode());
		obj.put("status",personNftApply.getStatus().toString());
		String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/unFreeze?";
		JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
		if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
			log.info("获取{}",jsonObject.getString("msg"));
			throw new YamiShopBindException(jsonObject.getString("msg"));
		}
	}

	@Override
	public List<DawToVo> getTransferPersonNftByApplyId(Long batchId) {
		TransferBatchApply transferBatchApply = transferBatchApplyService.selectIntoStautsByBatchId(batchId);
		if(transferBatchApply.getStatus()==7){
			throw new MailException("正在推送数据中");
		}
		if(transferBatchApply.getStatus()!=1){
			throw new MailException("状态异常");
		}
		PersonNftApply personNftApply = personNftApplyMapper.getinfoById(transferBatchApply.getApplyId());
		PersonnftProdVo productByProdId = productService.getPersonnftProdById(personNftApply.getProductId());
		if(Objects.isNull(productByProdId)){
			log.info("数据推送获取铸币商品信息异常申请id,{}",batchId);
			throw new MailException("获取商品信息异常");
		}
		PersonnftTansferEnpand byProId = nftTansferEnpandService.getByProId(personNftApply.getProductId());
		if(byProId==null){
			log.info("数据推送请先配置改藏品的品类映射申请id,{}",batchId);
			throw new MailException("请先配置改资产的品类映射");
		}
		List<String> strlist = Arrays.asList( transferBatchApply.getContent().split(","));
		//校验token
		List<TransferTokenRecord> records= transferTokenRecordService.selectListByTokenId(strlist,0);
		Map<String, TransferTokenRecord> collect = records.stream().collect(Collectors.toMap(TransferTokenRecord::getTokenId, Function.identity()));
		strlist.stream().forEach(s-> {
			if(ObjectUtil.isNotNull(collect.get(s))&&collect.get(s).getStatus()==0){
				throw new MailException("重复划转："+s);
			}
		});
		List<String> dawProductCodeList = Arrays.asList(transferBatchApply.getDawProductCode().split(","));
		if(strlist.size()!= personNftApply.getCount()||dawProductCodeList.size()!= personNftApply.getCount()){
			log.info("数据推送划转数量异常申请id,{}",batchId);
			throw new MailException("划转数量异常");
		}
		List<DawToVo> dawList = new ArrayList<>();
		getSendData(personNftApply, productByProdId, byProId, strlist, dawProductCodeList,dawList);
		return dawList;
	}



	@Override
	public void taskChekSendDataNfts() {
		TransferBatchApply transferBatchApply = TransferBatchApply.builder().status(1).times(10).orderBy("0").build();
		Page<TransferBatchApply> page = new PageParam();
		page.setCurrent(1);
		page.setSize(100);
		IPage<TransferBatchApply> transferBatchApplyIPage = transferBatchApplyService.selectPageList(page, transferBatchApply);
		List<TransferBatchApply> list = transferBatchApplyIPage.getRecords();
		if(list.size()==0){
			log.info("没有可以推送到海文交的数据");
			return;
		}
		for (TransferBatchApply nftApply:list) {
			try {
				sendAndDeletePersonNfts(nftApply.getBatchId());
			}catch (Exception e){
				log.info("划转海文交失败,{}",e.getMessage());
			}
		}
	}

	@Override
	@Transactional
	public void taskChekSendDataResult() {
		TransferApplyRecord record = new TransferApplyRecord();
		record.setType(0);//转出
		record.setStatus(1);//待查询
		List<TransferApplyRecord> list = transferApplyService.selectList(record);
		List<String> collect = list.stream().map(s -> s.getId()).collect(Collectors.toList());
		if(collect.size()==0){
			log.info("没有可查询划转的请求");
			return;
		}
		JSONArray res = wapiDawService.getChangeCeceiptResult(collect);
		log.info("查询返回的list数据{}",Json.toJsonString(res));
		for(int i=0;i<res.size();i++) {
			//收集不同查询结果记录集合
			JSONObject obj = res.getJSONObject(i);
			try{
				List<TransferBatchApply> batchList = new ArrayList<>();//批次表
				List<TransferApplyRecord> resList = new ArrayList<>();//推送表
				List<TransferApplyRecord> resSuccessList = new ArrayList<>(); //推送成功部分
				List<TransferApplyRecord> resErrorList = new ArrayList<>();//推送失败部分
				List<TransferApplyRecord> applyId = list.stream().filter(s -> s.getId().equals(obj.getString("applyId"))).collect(Collectors.toList());
				log.info("成功的批次对象{}",Json.toJsonString(applyId));
				TransferApplyRecord record1= applyId.get(0);
				record1.setTimes(record1.getTimes()+1);
				record1.setUpdateTime(DateUtil.date());
				if(obj.getString("isOk").equals("true")){
					TransferBatchApply transferBatchApply = TransferBatchApply.builder()
							.status(0).batchId(record1.getBatchId())//批次成功
							.build();
					batchList.add(transferBatchApply);
					record1.setStatus(0);
					resSuccessList.add(record1);
				}else if(obj.getString("isOk").equals("false")){
					TransferBatchApply transferBatchApply = TransferBatchApply.builder()
							.status(1).batchId(record1.getBatchId())//批次失败
							.build();
					batchList.add(transferBatchApply);
					record1.setStatus(2);
					resErrorList.add(record1);
				}else{
					record1.setMsg("处理中");
				}
				resList.add(record1);
				//修改推送记录表结果
				if(resList.size()>0){
					transferApplyService.updateBatch(resList);
				}
				if(batchList.size()>0){
					//修改批次记录
					transferBatchApplyService.updateBatch(batchList);
				}
				//处理成功
				List<String> applyIds = null;
				// 1 tokenid 池
				if(resSuccessList.size()>0){
					List<Long> batchIds = resSuccessList.stream().map(s -> s.getBatchId()).collect(Collectors.toList());
					applyIds = resSuccessList.stream().map(s -> s.getAppId()).distinct().collect(Collectors.toList());
					//修改token持仓
					transferTokenRecordService.updateBatchByBatchIdAndStatus(batchIds,0);
					log.info("划转完成的appIds,{}",applyIds);
				}
				//处理失败
				// 1 清空该tokenid 池
				if(resErrorList.size()>0){
					List<Long> batchIdsError = resErrorList.stream().map(s -> s.getBatchId()).collect(Collectors.toList());
					transferTokenRecordService.deteleBatchByBatchIds(batchIdsError);
					log.info("划转失败的batchIds，待下次在推送,{}",batchIdsError);
				}
				//处理持仓
				if(applyIds!=null){
					log.info("划转成功删除持仓，{}",applyIds);
					applicationContext.publishEvent(new DelPersonnftEvent(applyIds));
				}
			}catch (Exception e){
				log.info("划转查询异常的申请，{}",obj.getString("applyId"));
			}
		}

	}

	/**
	 * 校验批次完成删除持仓
	 * @param applyIds
	 */
	@Override
	public void chenAllBachIdDataResult(List<String> applyIds) {
		for (String applyId:applyIds) {
			Integer integer = transferBatchApplyService.selectCountByApplyId(applyId);
			log.info("applyId={},未处理完的数量={}",applyId,integer);
			if(integer==0){
				PersonNftApply personNftApply = PersonNftApply.builder()
						.status(1)
						.id(applyId)
						.updateTime(DateUtil.date())
						.build();
				personNftApplyMapper.update(personNftApply);
				//删除持仓
				personNftService.deleteThanserPersonNft(applyId);
			}
		}
	}
	@Override
	public String getLastSendData(String id) {
		return  transferBatchApplyService.selectProportionByApplyId(id);
	}

	@Override
	public String getCheckNftData(String id) {
		PersonNftApply nftApply = personNftApplyMapper.getinfoById(id);
		List<String> strlist = Arrays.asList( nftApply.getContent().split(","));
		int  count = 0 ;
		for (String tokenid: strlist) {
			PersonNft personNft = PersonNft.builder().tokenId(tokenid).userId(nftApply.getUserId()).status(1).build();
			List<PersonNft> lsit= personNftService.listByParam(personNft);
			if(lsit.size()==1 && "0".equals(lsit.get(0).getRemark())){
				count++;
			}
		}
		return  count+"/"+strlist.size();
	}

	/**
	 * 交收定时处理增加持仓
	 */
	@Override
	public void taskAddPersonVerifyNft() {
		PersonNftApply nftApply = PersonNftApply.builder().sceneType("2").status(0).build();
		PageDTO pageDTO = new PageDTO();
		pageDTO.setPageNum(1);
		pageDTO.setPageSize(10);
		PageVO<PersonNftApply> doPage = PageUtil.doPage( pageDTO, () -> personNftApplyMapper.listByParam(nftApply));
		List<PersonNftApply> listApply = doPage.getList();
		for (PersonNftApply personNftApply:listApply) {
			try {
				addPersonVerifyNft(personNftApply.getId());
			}catch (Exception e){
				log.info("划转海文交失败,{}",e.getMessage());
			}
		}
	}
	//交收定时处理增加持仓
	protected void addPersonVerifyNft (String appId){
		PersonNftApply personNftApply = personNftApplyMapper.getinfoById(appId);
		if(personNftApply.getStatus()==7){
			throw new MailException("正在处理数据中");
		}
		if(personNftApply.getStatus()!=0){
			throw new MailException("状态异常");
		}
		TransactionStatus transactionStatus1 = dataSourceTransactionManager.getTransaction(transactionDefinition);
		personNftApply.setStatus(7);
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
		dataSourceTransactionManager.commit(transactionStatus1);
		log.info("交收异步添加持仓开始================="+ Json.toJsonString(personNftApply));
		TransferApplyRecord record = transferApplyService.selectIntoStautsByAppId(appId);
		//事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		try {
			if("Y".equals(personNftApply.getIsListClick())){
				log.info("交收提现空投开始=================");
				//提现空投
				Product productByProdId = productService.getProductByProdId(personNftApply.getProductId());//暂时支持单次单人同一种商品
				eventPublisher.publishEvent(new WithdrawalNftEvent(appId,personNftApply.getProductId().toString(),productByProdId.getProdName(),personNftApply.getCount(),personNftApply.getUserId()));
				verifyUpdateStaus(appId,record,"1",null);
				//空投持仓到账后修改申请状态 和 transferApply状态
			}else if("1".equals(personNftApply.getChannelType())){
				log.info("dtc交收提现开始=================");
				//持仓托管户转移
				personNftService.addPersonNft(appId);
				//获取tokenIds
				List<String> strlist = Arrays.asList(personNftApply.getContent().split(","));
				//修改token池
				List<TransferTokenRecord> records= transferTokenRecordService.selectListByTokenId(strlist,0);
				for (TransferTokenRecord transferTokenRecord:records) {
					transferTokenRecord.setType(1);
					transferTokenRecord.setUpdateTime(DateUtil.date());
				}
				transferTokenRecordService.updateBatch(records);
				verifyUpdateStaus(appId,record,"1",null);
			}else if("2".equals(personNftApply.getChannelType())){
				log.info("dtc下游交收提现开始=================");
				//下游资产添加
				ChannelUserRelationRecord channelUserRelationRecord = channelUserRelationRecordService.getinfoByUserIdChainCodeChannelCode(personNftApply.getUserId(), personNftApply.getChainCode(), personNftApply.getChannelCode(), "2");
				Map<String,String> obj = new HashMap<>();
				obj.put("id",personNftApply.getDownApplyId());
				obj.put("type","1");
				obj.put("toUserId",channelUserRelationRecord.getChannelUserId());
				obj.put("tokenIds",personNftApply.getContent());
				obj.put("channelCode",personNftApply.getChannelCode());
				String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/transferPerson?";
				JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
				if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
					log.info("获取{}",jsonObject.getString("msg"));
					throw new YamiShopBindException(jsonObject.getString("msg"));
				}
				//获取tokenIds
				List<String> strlist = Arrays.asList(personNftApply.getContent().split(","));
				//修改token池
				List<TransferTokenRecord> records= transferTokenRecordService.selectListByTokenId(strlist,0);
				for (TransferTokenRecord transferTokenRecord:records) {
					transferTokenRecord.setType(1);
					transferTokenRecord.setUpdateTime(DateUtil.date());
				}
				transferTokenRecordService.updateBatch(records);
				PersonNftAccount personNftAccount = PersonNftAccount.builder().sceneType(Integer.valueOf(SceneType.AddByMarket.getCode())).content(personNftApply.getContent()).channelType(personNftApply.getChannelType()).chainCode(personNftApply.getChainCode()).channelCode(personNftApply.getChannelCode()).dawProductCode(personNftApply.getDawProductCode()).denomId(personNftApply.getDenomId()).userId(personNftApply.getUserId()).createTime(DateUtil.date()).id(IdUtil.getSnowflake().nextIdStr()).count(personNftApply.getCount()).productId(personNftApply.getProductId()).build();
				personNftAccountMapper.save(personNftAccount);
				verifyUpdateStaus(appId,record,"1",null);
			}
			//手动提交事务
			dataSourceTransactionManager.commit(transactionStatus);
		}catch (Exception e){
			log.info("交收异步添加持仓异常结束================="+ Json.toJsonString(personNftApply) + ","+e.getMessage());
			//手动回滚事务
			dataSourceTransactionManager.rollback(transactionStatus);
			TransactionStatus transactionStatus2 = dataSourceTransactionManager.getTransaction(transactionDefinition);
			//更新请求id
			String msg = getString(e);
			verifyUpdateStaus(appId,record,"2",msg);
			dataSourceTransactionManager.commit(transactionStatus2);
		}
	}
	//type 1 成功 2 失败
	@Override
	public void verifyUpdateStaus(String applyId,TransferApplyRecord record,String type,String msg){
		if(ObjectUtil.isNull(record)){
			record = transferApplyService.selectIntoStautsByAppId(applyId);
		}
		Integer status = 0;
		if("1".equals(type)){
			//更新提现申请状态
			status = 1;
			//更新请求id
			record.setStatus(0);//成功
		}else{
			record.setStatus(1);//待处理
			record.setMsg(msg);
			if(record.getTimes()>6){
				//恢复待定时器下次处理
				status = 2;
			}else {
				status = 0;
			}
		}
		record.setUpdateTime(new Date());
		record.setTimes(record.getTimes()+1);
		transferApplyService.updateByPrimaryKeySelective(record); //海文交查询
		PersonNftApply apply = PersonNftApply.builder().updateTime(DateUtil.date()).id(applyId).status(status).build();
		personNftApplyMapper.update(apply);
	}


	@Override
	@Synchronized
	public void sendAndDeletePersonNfts(Long batchId) {
		//通过
		TransferBatchApply transferBatchApply = transferBatchApplyService.selectIntoStautsByBatchId(batchId);
		if(transferBatchApply.getStatus()==7){
			throw new MailException("正在推送数据中");
		}
		if(transferBatchApply.getStatus()!=1){
			throw new MailException("状态异常");
		}
		PersonNftApply personNftApply = personNftApplyMapper.getinfoById(transferBatchApply.getApplyId());
		PersonnftProdVo productByProdId = productService.getPersonnftProdById(personNftApply.getProductId());
		if(Objects.isNull(productByProdId)){
			log.info("数据推送获取铸币商品信息异常申请id,{}",batchId);
			throw new MailException("获取商品信息异常");
		}
		PersonnftTansferEnpand byProId = nftTansferEnpandService.getByProId(personNftApply.getProductId());
		if(byProId==null){
			log.info("数据推送请先配置改藏品的品类映射申请id,{}",batchId);
			throw new MailException("请先配置改资产的品类映射");
		}
		List<String> strlist = Arrays.asList( transferBatchApply.getContent().split(","));
		//校验token
		List<TransferTokenRecord> records= transferTokenRecordService.selectListByTokenId(strlist,0);
		Map<String, TransferTokenRecord> collect = records.stream().collect(Collectors.toMap(TransferTokenRecord::getTokenId, Function.identity()));
		strlist.stream().forEach(s-> {
			if(ObjectUtil.isNotNull(collect.get(s))&&collect.get(s).getStatus()==0){
				throw new MailException("重复划转："+s);
			}
		});
		List<String> dawProductCodeList = Arrays.asList(transferBatchApply.getDawProductCode().split(","));
		if(strlist.size() > personNftApply.getCount()||dawProductCodeList.size() > personNftApply.getCount()){
			log.info("数据推送划转数量异常申请id,{}",batchId);
			throw new MailException("划转数量异常");
		}
		TransactionStatus transactionStatus1 = dataSourceTransactionManager.getTransaction(transactionDefinition);
		transferBatchApplyService.updateIntoStautsByBatchId(batchId,7,null,null);
		log.info("数据推送占用状态批次id,{}",batchId);
		dataSourceTransactionManager.commit(transactionStatus1);
		List<DawToVo> dawList = new ArrayList<>();
		//事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		//记录批次推送记录
		String applyHwjId= IdUtil.getSnowflake().nextIdStr();
		TransferApplyRecord transferApplyRecord = new TransferApplyRecord();
		transferApplyRecord.setId(applyHwjId);
		transferApplyRecord.setAppId(transferBatchApply.getApplyId());
		transferApplyRecord.setBatchId(batchId);
		transferApplyRecord.setCreateTime(DateUtil.date());
		transferApplyRecord.setType(0);//转出
		transferApplyRecord.setStatus(1);//失败
		transferApplyRecord.setTimes(0);
		try {
			getSendData(personNftApply, productByProdId, byProId, strlist, dawProductCodeList, dawList);
			//3修改申购记录状态  如果状态是1的待发送数据 发送成功或者超时为6 失败回滚1 ，后续查询成功为0 ，如果过查询没有成功退回为1
			transferBatchApplyService.updateIntoStautsByBatchId(batchId,6,null,transferBatchApply.getTimes()+1);
			log.info("数据推送申请id,{}",batchId);
			//保存token池
			saveRecord(transferBatchApply.getApplyId(),batchId, dawList);
			//推送
			wapiDawService.changeCeceipt(dawList,applyHwjId);
			//手动提交事务
			dataSourceTransactionManager.commit(transactionStatus);
		}catch (Exception e){
			e.printStackTrace();
			log.info("数据推送异常申请id,{},{}",batchId,e.getMessage());
			if(e.getMessage().contains("超时")){
				//手动提交事务
				dataSourceTransactionManager.commit(transactionStatus);
				throw new MailException(ResponseEnum.REQUESTS_TIME_OUT.value());
			}else{
				//手动回滚事务
				dataSourceTransactionManager.rollback(transactionStatus);
				//返回待发送状态
				TransactionStatus transactionStatus2 = dataSourceTransactionManager.getTransaction(transactionDefinition);
				transferBatchApplyService.updateIntoStautsByBatchId(batchId,1,e.getMessage(),transferBatchApply.getTimes()+1);
				//保存划转请求记录
				String msg = getString(e);
				transferApplyRecord.setStatus(2);//失败
				transferApplyRecord.setMsg(msg);
				dataSourceTransactionManager.commit(transactionStatus2);
			}
			throw new MailException(e.getMessage());
		}finally {
			//获取划转报文并保存
			String content = wapiDawService.getchangeCeceipt(dawList,applyHwjId);
			String content1 = content.length()>8000?content.substring(0,8000):content;
			transferApplyRecord.setContent(content1);
			//保存划转请求记录
			transferApplyService.save(transferApplyRecord);
		}
	}
	//组装推送数据
	private void getSendData(PersonNftApply personNftApply, PersonnftProdVo productByProdId, PersonnftTansferEnpand byProId, List<String> strlist, List<String> dawProductCodeList, List<DawToVo> dawList) {
		String denomId = personNftApply.getDenomId();
		String denomName = productByProdId.getDenomName();
		String mainImg = productByProdId.getPic();
		String dawName = productByProdId.getProdName();
		String author = productByProdId.getAuthorName();
		String issue = productByProdId.getIssueName();
		String fileType = productByProdId.getAttr().toString();
		String levelId = "";
		if(!Objects.isNull(productByProdId.getProdLevel()) && StrUtil.isNotEmpty(productByProdId.getProdLevel().getName())){
			levelId = productByProdId.getProdLevel().getName();
		}
		for (int i = 0 ;i<strlist.size();i++) {
			DawToVo dawToVo = DawToVo.builder()
					.denomId(denomId)
					.denomName(denomName)
					.tokenId(strlist.get(i))
					.mainImg(mainImg)
					.dawName(dawName)
					.author(author)
					.issue(issue)
					.fileType(getFileTypeName(fileType))
					.dawCode(dawProductCodeList.get(i))
					.levelId(levelId)
					.isClick(personNftApply.getIsListClick())
					.regWeight("1")
					.userId(personNftApply.getHwjUserId())
					.varietyCode(byProId.getVarietyCode())
					.build();
			dawList.add(dawToVo);
		}
	}

	@Override
	public void refundThansferPersonnft() {
		List<RersonnftThanfserRefund> initList = personnftThanfserRefundService.getInitList(50);
		for (RersonnftThanfserRefund rersonnftThanfserRefund: initList) {
			PersonNftApply personNftApply = personNftApplyMapper.getinfoById(rersonnftThanfserRefund.getApplyId());
			if(personNftApply.getStatus()==0){
				try{
					personNftApply.setStatus(3);
					transferReject(personNftApply);
					rersonnftThanfserRefund.setStatus(2);
					rersonnftThanfserRefund.setErrMsg("过期自动处理");
				}catch (Exception e){
					rersonnftThanfserRefund.setErrMsg(getString(e));
					rersonnftThanfserRefund.setStatus(3);
				}finally {
					rersonnftThanfserRefund.setUpdateTime(new Date());
					personnftThanfserRefundService.updateById(rersonnftThanfserRefund);
				}
			}else if(personNftApply.getStatus()==1 || personNftApply.getStatus()==2 ){
				rersonnftThanfserRefund.setStatus(2);
				rersonnftThanfserRefund.setUpdateTime(new Date());
				rersonnftThanfserRefund.setErrMsg("对方已接收或驳回");
				personnftThanfserRefundService.updateById(rersonnftThanfserRefund);
			}
		}
	}
	@Override
	public void changeCeceiptApplyNft() {
		TransferBatchApply transferBatchApply = TransferBatchApply.builder().status(4).times(20).orderBy("0").build();
		Page<TransferBatchApply> page = new PageParam();
		page.setCurrent(1);
		page.setSize(10);
		IPage<TransferBatchApply> transferBatchApplyIPage = transferBatchApplyService.selectPageList(page, transferBatchApply);
		List<TransferBatchApply> list = transferBatchApplyIPage.getRecords();
		if(list.size()==0){
			log.info("没有可以推送到海文交的数据");
			return;
		}
		//dtc通过  事务开启
		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		try {
			List<Long> collect = list.stream().map(s -> s.getBatchId()).collect(Collectors.toList());
			transferBatchApplyService.updateIntoStautsByBatchIds(collect,7);
			//手动提交事务
			dataSourceTransactionManager.commit(transactionStatus);
		}catch (Exception e){
			e.getMessage();
			//手动回滚事务
			dataSourceTransactionManager.rollback(transactionStatus);
			throw new YamiShopBindException(e.getMessage());
		}
		for (TransferBatchApply apply:list) {
			List<String> tokenIds = Arrays.asList(apply.getSurplusContent().split(","));
			PersonNftApply personNftApply = personNftApplyMapper.getinfoById(apply.getApplyId());
			Blockchain infoByCode = blockchainService.getInfoByCode(personNftApply.getChainCode());
			if("3".equals(personNftApply.getSceneType())){
				int  i = 0 ;
				List<String> resTokens = new ArrayList<>();
				for (String tokenId:tokenIds) {
					Map<String,String> obj = new HashMap<>();
					obj.put("nftId",tokenId);
					obj.put("denomId",personNftApply.getDenomId());
					obj.put("mnemonic",infoByCode.getMiddleMnemonic());
					obj.put("channelCode",personNftApply.getChannelCode());
					obj.put("chain",personNftApply.getChainCode());
					String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftmint/queryNFT?";
					try {
						JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
						log.info("查下结果{}{}",Json.toJsonString(jsonObject) ,jsonObject.getInteger("code"));
						if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
							log.info("获取{}",jsonObject.getString("msg"));
							resTokens.add(tokenId);
							log.info("校验到账失败{}",tokenId);
						}else{
							JSONObject data = jsonObject.getJSONObject("data");
							String owner = data.getString("owner");
							//检查资质是否到账
							if(infoByCode.getMiddleAddress().equals(owner)){
								log.info("校验到账成功2{}",tokenId);
								i++;
							}else{
								log.info("校验到账失败1{}",tokenId);
								resTokens.add(tokenId);
							}
						}
					}catch (Exception e){
						log.info("校验到账失败1{}",tokenId);
						resTokens.add(tokenId);
					}

				}
				log.info("校验到账集合={},成功数量={}",Json.toJsonString(resTokens),i);
				if(resTokens.size()>0){
					transferBatchApplyService.updateIntoSurplusContentByBatchId(apply.getBatchId(),apply.getTimes()+1, String.join(",",resTokens));
				}
				if(i==tokenIds.size()){
					//该批次全部到账
					transferBatchApplyService.updateIntoStautsByBatchId(apply.getBatchId(),1,null,null);
				}
			}else{
				ChannelUserRelationRecord record = channelUserRelationRecordService.getinfoByUserIdChainCodeChannelCode(personNftApply.getUserId(), personNftApply.getChainCode(), personNftApply.getChannelCode(), personNftApply.getChannelType());
				Map<String,Object> obj = new HashMap<>();
				obj.put("mnemonic",infoByCode.getMiddleMnemonic());
				obj.put("channelCode",personNftApply.getChannelCode());
				obj.put("chain",personNftApply.getChainCode());
				List<Map<String,String>> nftTransferRecordList = new ArrayList<>();
				for (String tokenId:tokenIds) {
					Map<String,String> nftTransferRecord = new HashMap<>();
					nftTransferRecord.put("nftId",tokenId);
					nftTransferRecord.put("denomId",personNftApply.getDenomId());
					nftTransferRecord.put("reci",record.getAddress());//获取用户
					nftTransferRecord.put("senderAddress",infoByCode.getMiddleAddress());
					nftTransferRecordList.add(nftTransferRecord);
				}
				obj.put("nftTransferRecordList",nftTransferRecordList);
				String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftmint/transferNFtMsg?";
				try {
					JSONObject jsonObject = dataWebService.hutoolPostObjWebService(url, obj,null,null);
					log.info("查下结果{}{}",Json.toJsonString(jsonObject) ,jsonObject.getInteger("code"));
					if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
						throw new YamiShopBindException(jsonObject.getString("msg"));
					}
					transferBatchApplyService.updateIntoStautsByBatchId(apply.getBatchId(),0,null,null);
				}catch (Exception e){
					log.info("提现下游资产转移{}",e.getMessage());
					transferBatchApplyService.updateIntoStautsByBatchId(apply.getBatchId(),4,null,apply.getTimes()+1);
				}
			}
		}
	}

	private String getString(Exception e) {
		String msg = "";
		if(StrUtil.isEmpty(e.getMessage())&& Arrays.toString(e.getStackTrace()).length()<=490){
			msg = "null--"+ Arrays.toString(e.getStackTrace()).substring(0);
		}else if(StrUtil.isEmpty(e.getMessage())&&Arrays.toString(e.getStackTrace()).length()>490){
			msg = "null--"+ Arrays.toString(e.getStackTrace()).substring(0,490);
		}else if(e.getMessage().length()>500){
			msg = e.getMessage().substring(0,500);
		}else{
			msg = e.getMessage().substring(0);
		}
		return msg;
	}
	private void saveRecord(String appId ,Long batchId, List<DawToVo> dawList) {
		//保存tokenId池 等查询成功结果后修改状态为成功，失败则删除该批次，提现前可以校验二次划转校验
		List<TransferTokenRecord> list = new ArrayList<>();
		for (DawToVo dawToVo: dawList) {
			TransferTokenRecord transferTokenRecord = new TransferTokenRecord();
			transferTokenRecord.setId(IdUtil.getSnowflake().nextIdStr());
			transferTokenRecord.setCreateTime(DateUtil.date());
			transferTokenRecord.setDenomeId(dawToVo.getDenomId());
			transferTokenRecord.setStatus(1);//失败
			transferTokenRecord.setType(0);//转出
			transferTokenRecord.setUserId(dawToVo.getUserId());
			transferTokenRecord.setTokenId(dawToVo.getTokenId());
			transferTokenRecord.setBatchId(batchId);
			transferTokenRecord.setAppId(appId);
			transferTokenRecord.setTimes(0);
			list.add(transferTokenRecord);
		}
		transferTokenRecordService.saveBatch(list);
	}


	@Override
	@Transactional
	public void changeCeceiptApply(String id, String status, String remark) {
		//2失败 1成功 0 申请
		if("2".equals(status)){
			rejectCeceiptApply(id,remark);
			return;
		}else if(StrUtil.isEmpty(status)){
			throw new YamiShopBindException("参数不能空");
		}
		//划转通过处理逻辑
		PersonNftApply personNftApply = personNftApplyMapper.getinfoById(id);
		PersonnftTansferEnpand byProId = nftTansferEnpandService.getByProId(personNftApply.getProductId());
		if(byProId==null){
			throw new MailException("请先配置改数产的品类映射");
		}
		List<AssetTrendsVO> trends = new ArrayList<>();
		List<String> strlist = Arrays.asList( personNftApply.getContent().split(","));
		if ("1".equals(personNftApply.getChannelType())){
			for (String tokenId: strlist) {
				//持仓删除
				PersonNft personNft = PersonNft.builder().tokenId(tokenId).userId(personNftApply.getUserId()).status(1).build();
				List<PersonNft> personNfts2 = personNftMapper.listByParam(personNft);
				if (personNfts2.size() != 1) {
					log.info("审核-划转持仓数据异常，转增记录id=" + id);
					throw new YamiShopBindException("划转持仓数据异常");
				}
				AssetTrendsVO trendVO = AssetTrendsVO.builder()
						.denomId(personNftApply.getDenomId()).tokenId(tokenId).fromUserId(personNftApply.getUserId()).price(0.00).outId(id).prodId(personNftApply.getProductId())
						.build();
				trends.add(trendVO);
			}
		}
		//审核成功并转移资产
		personNftApply.setStatus(7);//处理中
		personNftApply.setUpdateTime(DateUtil.date());
		personNftApplyMapper.update(personNftApply);
		//根据申请记录拆分集合
		List<TransferBatchApply> listBatch = new ArrayList<>();
		String transfeTMaxCount = shopConfig.getTransfeTMaxCount();
		List<String> codelist = Arrays.asList( personNftApply.getDawProductCode().split(","));
		List<List<String>> tokens = Lists.partition(strlist, Integer.valueOf(transfeTMaxCount));
		List<List<String>> codes = Lists.partition(codelist, Integer.valueOf(transfeTMaxCount));
		if(tokens.size()!=codes.size()){
			throw new YamiShopBindException("tokenId数量和编码数据异常");
		}
		//资产分组，方便后续处理 ---海文交每次发送上限100
		for (int i =0 ;i<tokens.size(); i++){
			List<String> tokenList = tokens.get(i);
			List<String> codeList = codes.get(i);
			TransferBatchApply transferBatchApply = TransferBatchApply.builder()
				.applyId(personNftApply.getId())
				.content(tokenList.stream().collect(Collectors.joining(",")))
				.dawProductCode(codeList.stream().collect(Collectors.joining(",")))
				.status("1".equals(personNftApply.getChannelType())?1:4)  //dtc待推送 下游待资产转移
				.times(0)
				.createTime(new Date())
				.chainCode(personNftApply.getChainCode())
				.channelCode(personNftApply.getChannelCode())
				.channelType(personNftApply.getChannelType())
				.surplusContent("1".equals(personNftApply.getChannelType())?null:tokenList.stream().collect(Collectors.joining(",")))
				.build();
			listBatch.add(transferBatchApply);
		}
		transferBatchApplyService.saveBatch(listBatch);
		if("1".equals(personNftApply.getChannelType())){
			//转移资产记账
			applicationContext.publishEvent(new AssetTrendsEvent(TradeType.ROLL_OUT.getValue(), trends));
		}else{
			//下游通知资产转移
			Map<String,String> obj = new HashMap<>();
			obj.put("id",personNftApply.getDownApplyId());
			obj.put("channelCode",personNftApply.getChannelCode());
			String url = shopConfig.getApiGatewayUrl() + "/personnft/outapi/app/personnftApply/changeCeceiptApplyNft?";
			JSONObject jsonObject = dataWebService.hutoolPostWebService(url, obj,null,null);
			if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
				log.info("获取{}",jsonObject.getString("msg"));
				throw new YamiShopBindException(jsonObject.getString("msg"));
			}
		}

	}

	private String updateSourceImg(Map<String, Object> keyWordMap, String sourceUrlPdf) {
		try{
			Minio minio = shopConfig.getMinio();
			URL url = new URL(minio.getEndpoint() + "/" + minio.getBucketName() + "/" + sourceUrlPdf);
			URLConnection urlConnection = url.openConnection();
			urlConnection.connect();
			ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
			PdfUtils.generatePdf(urlConnection.getInputStream(), qrOutputStream, keyWordMap,null,85f);
			//保存图片
			PDDocument document = PDDocument.load(qrOutputStream.toByteArray());
			PDFRenderer pdfRenderer = new PDFRenderer(document);
			BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300); // 使用300dpi解析第一页，可以自行调整dpi大小
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			ImageIO.write(image, "JPEG", outputStream);
			MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", outputStream.toByteArray());
			return attachFileService.uploadFile(ossMultipartFile.getBytes(), UUID.randomUUID() + ".jpg");
		}catch (Exception e){
			log.error("PDF生成异常{}",e);
			return "";
		}
	}

	private String getFileTypeName (String fileType){
		if(StringUtil.isEmpty(fileType)){
			return null;
		}
		String fileTypeName = "";
		switch(fileType){
			case "1" :
				fileTypeName = "图片";
				break; //可选
			case "2"  :
				fileTypeName = "音频";
				break; //可选
			case "3"  :
				fileTypeName = "文件";
				break; //可选
			case "4"  :
				fileTypeName = "3d";
				break; //可选
		}
		return fileTypeName;
	}
}
